package com.dc.service;


import com.dc.constant.Constants;
import com.dc.constant.MessageConstant;
import com.dc.dao.ConfigDao;
import com.dc.dao.EnergyCompanyDao;
import com.dc.dao.EnergyMonitorDao;
import com.dc.entity.ConfigEntity;
import com.dc.entity.EnergyCompanyEntity;
import com.dc.entity.EnergyMonitorEntity;
import com.dc.exception.ServiceException;
import com.dc.model.AjaxResult;
import com.dc.model.EnergyMonitorBody;
import com.dc.model.EnergyMonitorChildBody;
import com.dc.model.EnergyMonitorSearchBody;
import com.dc.service.dto.CMonitorChildDto;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 内部监控、碳核查 相关计算
 */
@Service
public class EnergyMonitorService {

    @Resource
    private EnergyCompanyDao energyCompanyDao;

    @Resource
    private EnergyMonitorDao energyMonitorDao;

    @Resource
    private ConfigDao configDao;



    ////////////////////////////////////////////////////// 总物量  //////////////////////////////////////////////////////
    /**
     * 总物量对外接口
     * @param energyMonitorBody
     * @return
     */
    public List<EnergyMonitorChildBody> getEnergyMonitor(EnergyMonitorSearchBody energyMonitorBody) {
        String company = energyMonitorBody.getCompany();
        if(Constants.NAME_COMPANY_ZIZHOU.equals(company)) {
            return getZiZhouEnergyMonitor(energyMonitorBody);
        } else if(Constants.NAME_COMPANY_YOU.equals(company) || Constants.NAME_COMPANY_ZHAO.equals(company)) {
            return getCommonEnergyMonitor(energyMonitorBody);
        } else {
            throw new ServiceException(MessageConstant.ERR_COMPANY_NAME);
        }
    }

    /**
     * 计算 友联船厂  招商重工  的 总物量
     * @param energyMonitorBody
     * @return
     */
    private List<EnergyMonitorChildBody> getCommonEnergyMonitor(EnergyMonitorSearchBody energyMonitorBody) {

        String company = energyMonitorBody.getCompany();
        Integer type = energyMonitorBody.getType();
        Integer year = energyMonitorBody.getYear();

        EnergyCompanyEntity entity = new EnergyCompanyEntity(null, company, type, year);
        List<EnergyCompanyEntity> one = energyCompanyDao.findAll(Example.of(entity));

        if(ObjectUtils.isEmpty(one)) {          // 没有企业数据
            return new ArrayList<>();
        }

        EnergyCompanyEntity entity1 = one.get(0);
        Long companyId = entity1.getId();

        // 查询 EnergyMonitor 处理数据
        List<EnergyMonitorEntity> monitorEntityList = energyMonitorDao.findByCompanyId(companyId);

        if(ObjectUtils.isEmpty(monitorEntityList)) {    // 如果实物量为空，则返回null
            return new ArrayList<>();
        }

        // 组装结果
        List<EnergyMonitorChildBody> result = new ArrayList<>();

        for(EnergyMonitorEntity e : monitorEntityList) {
            EnergyMonitorChildBody childBody = new EnergyMonitorChildBody();
            childBody.setId(e.getId());
            childBody.setName(e.getName());
            childBody.setUnit(e.getUnit());
            childBody.setRatio(e.getRatio());

            ConfigEntity config = configDao.findByYearAndName(year, e.getName());
            try {
                Double factor = ObjectUtils.isEmpty(config) ? 0. : config.getValue();
                childBody.setFactor(factor);
            } catch (Exception e1) {
                childBody.setFactor(0.);
            }


            String[] monthArr = e.getMonths().split(",");
            List<Double> monthsList = new ArrayList<>();
            Double sum = 0.;
            for(String mStr : monthArr) {
                Double mDouble = Double.valueOf(mStr);
                monthsList.add(mDouble);
                sum += mDouble;
            }

            childBody.setSum(sum);
            childBody.setMonths(monthsList);

            result.add(childBody);
        }

        return result;
    }

    /**
     * 计算 孖洲岛 的 总物量 信息
     */
    private List<EnergyMonitorChildBody> getZiZhouEnergyMonitor(EnergyMonitorSearchBody energyMonitorBody) {

        String company = energyMonitorBody.getCompany();

        if(!Constants.NAME_COMPANY_ZIZHOU.equals(company)) {                // 此方法计算 孖洲岛 的总物量，其他船厂不适合
            throw new ServiceException(MessageConstant.ERR_COMPANY_ENERGY);
        }

        EnergyMonitorSearchBody zhou = new EnergyMonitorSearchBody(Constants.NAME_COMPANY_ZHAO,
                energyMonitorBody.getType(), energyMonitorBody.getYear());
        List<EnergyMonitorChildBody> zhouEnergyMonitor = getCommonEnergyMonitor(zhou);

        EnergyMonitorSearchBody you = new EnergyMonitorSearchBody(Constants.NAME_COMPANY_YOU,
                energyMonitorBody.getType(), energyMonitorBody.getYear());
        List<EnergyMonitorChildBody> youEnergyMonitor = getCommonEnergyMonitor(you);


        return mergeEnergyMonitor(zhouEnergyMonitor, youEnergyMonitor);

    }

    /**
     * 计算 孖洲岛 的总物量
     * @param zhouEnergyMonitors
     * @param youEnergyMonitors
     * @return
     */
    private List<EnergyMonitorChildBody> mergeEnergyMonitor(List<EnergyMonitorChildBody> zhouEnergyMonitors, List<EnergyMonitorChildBody> youEnergyMonitors) {

        if(ObjectUtils.isEmpty(zhouEnergyMonitors) && ObjectUtils.isEmpty(youEnergyMonitors)) {
            return new ArrayList<>();
        } else if(ObjectUtils.isEmpty(zhouEnergyMonitors) && !ObjectUtils.isEmpty(youEnergyMonitors)) {
            return youEnergyMonitors;
        } else if(!ObjectUtils.isEmpty(zhouEnergyMonitors) && ObjectUtils.isEmpty(youEnergyMonitors)) {
            return zhouEnergyMonitors;
        }

        List<EnergyMonitorChildBody> result = new ArrayList<>();

        for(EnergyMonitorChildBody zhouEn : zhouEnergyMonitors) {

            Iterator<EnergyMonitorChildBody> iterator = youEnergyMonitors.iterator();

            boolean flag = false;

            while (iterator.hasNext()) {

                EnergyMonitorChildBody youEn = iterator.next();

                String zhouName = zhouEn.getName();
                String youName = youEn.getName();
                if(zhouName.equals(youName)) {          // 相同的能源 开始相加

                    flag = true;

                    EnergyMonitorChildBody entity = new EnergyMonitorChildBody();
                    entity.setName(youName);
                    entity.setUnit(youEn.getUnit());
                    entity.setFactor(youEn.getFactor());
                    entity.setRatio(youEn.getRatio());
                    List<Double> youEnMonths = youEn.getMonths();
                    List<Double> zhouEnMonths = zhouEn.getMonths();

                    for(int i = 0; i < youEnMonths.size(); i++) {
                        entity.getMonths().add(youEnMonths.get(i) + zhouEnMonths.get(i));
                        Double sum = ObjectUtils.isEmpty(entity.getSum()) ? 0. : entity.getSum();
                        entity.setSum(sum + zhouEnMonths.get(i) + youEnMonths.get(i));
                    }

                    result.add(entity);

                    iterator.remove();  // 操作一个就删除一个
                }
                if (flag) {
                    continue;
                }
                // flag = false 没有匹配，直接添加
                result.add(zhouEn);
            }
        }
        // 结束，如果youCMList还有元素，加进来
        if(!youEnergyMonitors.isEmpty()) {
            result.addAll(youEnergyMonitors);
        }

        return result;
    }

    ////////////////////////////////////////////////////////////////  计算 碳排放
    /**
     * 计算 友联船厂  和  招商重工 和 孖洲岛 的碳排，通用方法
     * @param energyMonitorBody
     * @return
     */
    public List<CMonitorChildDto> getCMonitor(EnergyMonitorSearchBody energyMonitorBody) {

        int year = energyMonitorBody.getYear();
        int type = energyMonitorBody.getType();

        List<CMonitorChildDto> result = new ArrayList<>();

        EnergyMonitorChildBody allProduce = null;       // 总产值的行

        List<EnergyMonitorChildBody> energyMonitor = getEnergyMonitor(energyMonitorBody);

        if(ObjectUtils.isEmpty(energyMonitor)) {        // 如果没有数据，则返回空list
            return new ArrayList<>();
        }

        for(EnergyMonitorChildBody body : energyMonitor) {  // 开始转化
            if(Constants.NAME_C_MONITOR_EXCLUDE.equals(body.getName())) {       // 找出总产值, 并且过滤掉，碳排放没有总产值行
                allProduce = body;
                continue;
            }
            String name = body.getName();
            Double factor = body.getFactor();

            CMonitorChildDto dto = new CMonitorChildDto();
            dto.setName(name);
            dto.setFactor(factor);               // 配置表获取 factor
            List<Double> dtoMonths = dto.getMonths();
            List<Double> bodyMonths = body.getMonths();
            double sum = 0.;
            for(int i = 0; i < bodyMonths.size(); i++) {
                double dtoM = dto.getFactor() * bodyMonths.get(i) * body.getRatio();
                dtoMonths.add(dtoM);
                sum += dtoM;
            }
            dto.setSum(sum);

            result.add(dto);
        }

        // 添加 碳排放量-深圳指南 行
        CMonitorChildDto shenzhenDto = new CMonitorChildDto();
        shenzhenDto.setName(Constants.NAME_C_SHENZHEN_INCLUDE);

        List<Double> dtoMonths = shenzhenDto.getMonths();
        for(int i = 0; i < 12; i++) {
            dtoMonths.add(0.);
        }

        Double sum = 0.;

        for(CMonitorChildDto monitorEntity : result) {

            List<Double> monitorMons = monitorEntity.getMonths();

            for(int i = 0; i< monitorMons.size(); i++) {
                Double v = monitorMons.get(i);
                dtoMonths.set(i, dtoMonths.get(i) + v);

            }

            sum += monitorEntity.getSum();
        }

        shenzhenDto.setSum(sum);

        result.add(shenzhenDto);

        // 如果是 孖洲岛 的 内部监控
        // 添加单独的行
        //      1.  碳排放量月度/年度指标
        //      2.  碳排放强度(深圳指南）（t/万元）
        //      3.  碳排放强度月度/年度指标（t/万元）
        String company = energyMonitorBody.getCompany();
        if(Constants.NAME_COMPANY_ZIZHOU.equals(company)
                && Constants.TYPE_DC_IN_MONITOR.equals(type)) {
            ////////////////////////////////////
            // 1. 碳排放量月度/年度指标
            CMonitorChildDto cFlagChildDto = new CMonitorChildDto();
            cFlagChildDto.setName(Constants.NAME_C_FLAG_INCLUDE);

            Double total = 0.;
            ConfigEntity cFlagConfig = configDao.findByYearAndName(year, Constants.NAME_C_FLAG_INCLUDE);

            if(!ObjectUtils.isEmpty(cFlagConfig)) {
                total = cFlagConfig.getValue();
            }

            // 1 到 11 月 为 begin , 12 月 为 end
            cFlagChildDto.getMonths().addAll(getCMonthFlagsList(total));
            cFlagChildDto.setSum(total);

            result.add(cFlagChildDto);

            // 2. 碳排放强度月度/年度指标
            CMonitorChildDto cPowerFlagChildDto = new CMonitorChildDto();
            cPowerFlagChildDto.setName(Constants.NAME_C_POWER_FLAG_INCLUDE);
            ConfigEntity cPowerFlagConfig = configDao.findByYearAndName(year, Constants.NAME_C_POWER_FLAG_INCLUDE);
            Double power = 0.;
            if(!ObjectUtils.isEmpty(cPowerFlagConfig)) {
                power = cPowerFlagConfig.getValue();
            }

            // 1 到 12 月 的碳强指标相等
            for(int i = 0; i < 12; i++) {
                cPowerFlagChildDto.getMonths().add(power);
            }
            cPowerFlagChildDto.setSum(power);

            result.add(cPowerFlagChildDto);

            // 3. 碳排放强度-深圳指南  ==>  碳排放量(深圳指南） / 总产值
            // 查询数据库 得到
            CMonitorChildDto cChildDto = new CMonitorChildDto();
            cChildDto.setName(Constants.NAME_C_POWER_INCLUDE);
            List<Double> cChildMonths = cChildDto.getMonths();

            for(int i = 0; i < 12; i++) {
                cChildMonths.add(0.);
            }

            // 找到 总物量 的  总产值 ， 找到 碳排放 的 碳排放量(深圳指南）
//            allProduce  shenzhenDto
            List<Double> allProduceMonths = allProduce.getMonths();
            List<Double> shenzhenDtoMonths = shenzhenDto.getMonths();
            for (int i = 0; i < 12; i++) {
                Double allProduceM = allProduceMonths.get(i);
                Double shenzhenM = shenzhenDtoMonths.get(i);
                try {
                    Double qiangdu = shenzhenM / allProduceM;
                    if(Double.isNaN(qiangdu)) {
                        qiangdu = 0.;
                    }
                    cChildMonths.set(i, qiangdu);
                } catch (Exception e) {
                    cChildMonths.set(i, 0.);
                }
            }

            try {
                cChildDto.setSum(shenzhenDto.getSum() / allProduce.getSum());
            } catch (Exception e) {
                cChildDto.setSum(0.);
            }

            result.add(cChildDto);
        }

        return result;
    }

    /**
     * 计算碳排放量月度/年度指标
     * @param total
     * @return
     */
    public List<Double> getCMonthFlagsList(Double total) {
        int totalInt = total.intValue();
        int begin = (int)(totalInt/12);
        int end = begin + totalInt % 12;
        List<Double> monthList = new ArrayList<>();
        for(int i = 0; i < 11; i++) {
            monthList.add((double)begin);
        }
        monthList.add((double)end);

        return monthList;
    }

    // 基础操作
    public List<EnergyMonitorChildBody> insertOrUpdate(EnergyMonitorBody energyMonitorBody) {

        String company = energyMonitorBody.getCompany();
        Integer type = energyMonitorBody.getType();
        Integer year = energyMonitorBody.getYear();

        EnergyCompanyEntity entity = new EnergyCompanyEntity(null, company, type, year);
        List<EnergyCompanyEntity> one = energyCompanyDao.findAll(Example.of(entity));

        EnergyCompanyEntity entity1 = null;

        if(ObjectUtils.isEmpty(one)) {          // 没有数据, 新增
            EnergyCompanyEntity companyEntity = new EnergyCompanyEntity();
            companyEntity.setType(type);
            companyEntity.setCompany(company);
            companyEntity.setYear(year);
            entity1 = energyCompanyDao.save(companyEntity);
        } else {
            entity1 = one.get(0);
        }

        Long companyId = entity1.getId();

        // 删除 company, type, year 的 EnergyMonitor 记录
        energyMonitorDao.deleteByCompanyId(companyId);

        List<EnergyMonitorChildBody> list = energyMonitorBody.getList();

        if(ObjectUtils.isEmpty(list)) {
            throw new ServiceException(MessageConstant.ERR_TABLE_DATA_NULL);
        }

        List<EnergyMonitorEntity> energyMonitorEntities = list.stream().map(t -> {
            EnergyMonitorEntity childBody = new EnergyMonitorEntity();
            childBody.setId(null);              // 删除旧的，每次更新
            childBody.setName(t.getName());
            childBody.setUnit(t.getUnit());

            childBody.setFactor(0.);        // 废除

            childBody.setRatio(t.getRatio());

            String monthsStr = t.getMonths().stream().map(String::valueOf).collect(Collectors.joining(","));
            childBody.setMonths(monthsStr);

            childBody.setCompanyId(companyId);

            return childBody;

        }).collect(Collectors.toList());

        // 保存并返回保存的数据
        List<EnergyMonitorEntity> monitorEntityListDB = energyMonitorDao.saveAll(energyMonitorEntities);

        // 返回给客户端
        List<EnergyMonitorChildBody> childBodyList = monitorEntityListDB.stream().map(t -> {
            EnergyMonitorChildBody childBody = new EnergyMonitorChildBody();
            childBody.setId(t.getId());              // 删除旧的，每次更新
            childBody.setName(t.getName());
            childBody.setUnit(t.getUnit());

            ConfigEntity config = configDao.findByYearAndName(year, t.getName());
            try {
                childBody.setFactor(config.getValue());        // 废除
            } catch (Exception e) {
                childBody.setFactor(0.);
            }

            childBody.setRatio(t.getRatio());

            String[] mStr = t.getMonths().split(",");
            Double sum = 0.;
            for (int i = 0; i < mStr.length; i++) {
                Double v = Double.valueOf(mStr[i]);
                childBody.getMonths().add(v);
                sum += v;
            }

            childBody.setSum(sum);
            return childBody;

        }).collect(Collectors.toList());

        return childBodyList;
    }

}
